#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@File   : test13_security_p1.py
@Time : 2025/3/11 11:15
@Author: Wangwc
@Describe:  ……
"""
import time
import os
import allure
import pytest
import random
import warnings

warnings.filterwarnings("ignore", category=DeprecationWarning)
from urllib3.exceptions import InsecureRequestWarning

warnings.simplefilter('ignore', category=InsecureRequestWarning)

from utils.network_tools import Network
from business.NetworkApi import NetworkApi
from utils.login import Login
from commons.logger import log
from utils.config_tools import Config
from commons.fake_data import Fake
from config.path import CERTS_DIR


# TODO 当前模块的配置文件名称，配置在config目录下
config_name = "user.ini"
login = Login(config_name=config_name)
config = Config(config_name=config_name)

global_token = None

@pytest.fixture(scope="function")
def network_api():
    global global_token
    if global_token is None:
        login.http_request.update_base_url()
        global_token = login.login()
    api = NetworkApi(global_token, configname=config_name)
    # 动态更新 base_url
    api.http.update_base_url()
    return api


def handle_api_call(api_method, *args, attach_to_allure=True, format_result=None, **kwargs):
    if not callable(api_method):
        raise TypeError("api_method 参数必须是可调用对象（如函数或方法）")
    if attach_to_allure is not None and not isinstance(attach_to_allure, bool):
        raise TypeError("attach_to_allure 参数必须是布尔类型或者为 None")
    if format_result is not None and not callable(format_result):
        raise TypeError("format_result 参数必须是可调用对象（如函数）或者为 None")

    max_retries = 3
    for retry in range(max_retries):
        try:
            result = api_method(*args, **kwargs)
            if attach_to_allure:
                if format_result:
                    formatted_result = format_result(result)
                else:
                    formatted_result = str(result)
                allure.attach(formatted_result, f"{api_method.__name__} 调用结果", allure.attachment_type.TEXT)
            log.info(f"{api_method.__name__} 调用成功")
            return result
        except Exception as e:
            allure.attach(str(e), f"{api_method.__name__} 调用错误信息", allure.attachment_type.TEXT)
            log.error(f"{api_method.__name__} 调用出现错误: {e}", exc_info=True)
            # 假设根据错误信息判断 token 过期
            if "token 过期" in str(e) and retry < max_retries - 1:
                global global_token
                global_token = login.login()
                api_method.__self__.token = global_token
                continue
            elif isinstance(e, ConnectionError):
                log.error("连接错误，可能是网络问题，请检查网络连接。")
            elif isinstance(e, ValueError):
                log.error("值错误，可能是传入的参数有误，请检查参数。")
            raise

host = config.read_config_ini('envHost','hostname')
username = config.read_config_ini('user','user_name')
passwd = config.read_config_ini('user','user_pwd')


@allure.feature("控制面板-网络&安全-P1级用例")
class TestSystemNetwork:
    @pytest.fixture(autouse=True)
    def setup_teardown(self, network_api):
        self.api = network_api
        # 测试前清理所有防火墙规则
        handle_api_call(self.api.del_all_firewall_rule)
        yield
        # 测试后清理所有防火墙规则
        handle_api_call(self.api.del_all_firewall_rule)

    # 参数化测试数据
    SERVICE_TEST_CASES = [
        ("SSH+UGOS","SSH", 'check_ssh_login','check_http', 'check_smb_login'),
        ("SMB+UGOS", "SMB", 'check_smb_login','check_http', 'check_ssh_login'),
        ("Telnet+UGOS","Telnet", 'check_telnet_login', 'check_http','check_ssh_login'),
        ("FTP+UGOS","FTP",  'check_ftp_login', 'check_http','check_ssh_login'),
        ("WebDAV+UGOS","WebDAV", 'check_webdav_access','check_http', 'check_ssh_login'),
        ("rsync+UGOS","rsync", 'check_rsync_access','check_http', 'check_ssh_login'),
        ("wsdd2+UGOS","wsdd2", 'check_wsdd2_access', 'check_http','check_ssh_login')
    ]

    @pytest.mark.parametrize("case_name,service_name,allowed_check1,allowed_check2,denied_checks", SERVICE_TEST_CASES)
    @allure.title("防火墙功能-规则都不符合时拒绝访问-允许所有网口的{case_name}端口")
    def test_firewall_ruler(self, network_api,case_name,service_name,allowed_check1,allowed_check2, denied_checks):
        with allure.step("获取设置防火墙规则的参数"):
            rsync_info = handle_api_call(network_api.application_info_by_service_name, case_name)
            ugos_info = handle_api_call(network_api.application_info_by_service_name, 'UGOS Pro')
            internal_servers = [rsync_info.get('name'), ugos_info.get('name')]
            sections = [rsync_info.get('section'), ugos_info.get('section')]
            ports = ",".join([rsync_info.get('ports'), ugos_info.get('ports')])

        with allure.step("设置防火墙规则"):
            request_data = {}
            name = Fake.fake_name()
            name_list = [{"id": 1, "name": f"防火墙配置{name}", "enable": 1}]
            default = 0
            port_info = {"type": "sys", "protocol": "", "target": "", "ports": "", "internal_servers": [],
                         "sections": []}
            host_info = {"type": "all", "src_ip": ""}
            port_info.update({"ports": ports, "internal_servers": internal_servers, "sections": sections})
            request_data.update(
                {"name": f"防火墙配置{name}", "default": default, "port_info": port_info, "host_info": host_info})
            handle_api_call(network_api.add_firewall_rule, **request_data)
            handle_api_call(network_api.set_firewall, nameList=name_list)

        with allure.step("验证web服务可以访问"):
            web_result = handle_api_call(network_api.allowed_check1, host, username)
            assert web_result[0] == True, "web服务无法访问"

        with allure.step(f"验证{service_name}服务可以访问"):
            port = rsync_info.get('ports')
            rsync_result = handle_api_call(network_api.allowed_check2, host, username=username, password=passwd,
                                           port=port)
            assert rsync_result[0] == True, "rsync服务无法访问"

        with allure.step("验证SSH不可以访问"):
            ssh_result = handle_api_call(network_api.denied_check, host, username, passwd)
            assert ssh_result[0] == False, "SSH服务可以访问"

        with allure.step("删除防火墙规则"):
            handle_api_call(network_api.del_firewall_rule, name_list)
